import src.TinyLock;
public class BootStrap{
    public static void main(String[] args){
        BootStrap bootStrap = new BootStrap();
        bootStrap.concurrentExecute(10);
        bootStrap.printInTurn(100);
        bootStrap.reentrantLockTest(5);
    }
    /**
     * 测试用例1，多个线程并发执行，通过加锁让其串行化打印
     */
    public void concurrentExecute(int runNums){
        TinyLock lock = new TinyLock();
        for(int i=0;i<runNums;i++){
            new Thread(()->{
                lock.lock();
                System.out.printf("当前是线程:%s在执行\n",Thread.currentThread());
                lock.release();
            }).start();
        }
        for(int i=0;i<runNums/2;i++){
            new Thread(()->{
                lock.lock();
                System.out.printf("当前是线程:%s在执行\n",Thread.currentThread());
                lock.release();
            }).start();
        }
    }
    /**
     * 测试用例2，两个线程交替打印数字
     */
    private volatile int start = 0;
    public void printInTurn(int rightBoundry){
        TinyLock lock = new TinyLock();
        Thread odd = new Thread(()->{
            /**
             * 2次检查是有必要的
             * 1.外层的判断方便快速失败
             * 2.内层的判断是在加锁后进行二次检查
             */
            while(start<rightBoundry){
                lock.lock();
                try {
                    if (start % 2 == 0 && start < rightBoundry) {
                        start++;
                        System.out.printf("奇数线程:%d\n", start);
                    }
                } finally {
                    lock.release();
                }  
            }
        });
        Thread even = new Thread(()->{
            while(start<rightBoundry){
                lock.lock();
                try {
                    if (start % 2 == 1 && start < rightBoundry) {
                        start++;
                        System.out.printf("偶数线程:%d\n", start);
                    }
                } finally {
                    lock.release();
                }
            }            
        });
        odd.start();
        even.start();
    }
    /**
     * 测试用例3，测试可重入锁的能力
     */
    public void reentrantLockTest(int reentrantTimes){
        TinyLock lock = new TinyLock();
        new Thread(() -> {
            try {
                // 重入获取锁
                for(int i = 0; i < reentrantTimes; i++) {
                    lock.lock();
                    System.out.printf("第%d次重入获取锁, holdCount=%d\n", 
                        i+1, lock.getHoldCount());
                }
                
                // 临界区
                System.out.printf("可重入锁测试:%s在执行\n", Thread.currentThread());
                
            } finally {
                // 逐层释放
                for(int i = 0; i < reentrantTimes; i++) {
                    System.out.printf("第%d次释放锁, holdCount=%d\n", 
                        i+1, lock.getHoldCount());
                    lock.release();
                }
            }
        }).start();
        
        // 添加一个竞争线程测试是否真的互斥
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("竞争线程成功获取锁");
            } finally {
                lock.release();
            }
        }).start(); 
    }
    
}
